﻿using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
using System.Windows.Input;
using Microsoft.Phone.UserData;
using MobiSms.DataModel;
using MobiSms.Enums;
using MobiSms.Library;
using System;
using MobiSms.Library.Extensions;

namespace MobiSms.ViewModel
{
    public class MessageComposeViewModel : MainViewModel
    {
        #region Constructor
        private Contacts contacts = new Contacts();

        public MessageComposeViewModel()
        {
            contacts.SearchCompleted -= contacts_SearchCompleted;
            contacts.SearchCompleted += contacts_SearchCompleted;
            if (!IsDesignMode)
            {
                contacts.SearchAsync("", FilterKind.None, null);
            }

            SoapClient.SendSMSCompleted -= SoapClientSendSMSCompleted;
            SoapClient.SendSMSCompleted += SoapClientSendSMSCompleted;

            NewContactToAdd.ValueChanged -= NewContactValueChanged;
            NewContactToAdd.ValueChanged += NewContactValueChanged;

            NewMessageToSend.ValueChanged -= NewMessageValueChanged;
            NewMessageToSend.ValueChanged += NewMessageValueChanged;
        }

        #endregion

        #region Properties
        private ObservableCollection<ContactInfo> _itemsOfContact = new ObservableCollection<ContactInfo>();
        public ObservableCollection<ContactInfo> ItemsOfContact
        {
            get { return _itemsOfContact; }
            set
            {
                _itemsOfContact = value;
                RaisePropertyChanged(() => ItemsOfContact);
                RaisePropertyChanged(() => SelectedCount);
                RaisePropertyChanged(() => CleanCommand);
                RaisePropertyChanged(() => TotleSendCount);
                RaisePropertyChanged(() => SubmitCommand);
            }
        }
        
        private ContactInfo _newContactToAdd = new ContactInfo();
        public ContactInfo NewContactToAdd
        {
            get { return _newContactToAdd; }
            set
            {
                _newContactToAdd = value;
                RaisePropertyChanged(() => NewContactToAdd);

            }
        }

        private MessageInfo _newMessageToSend = new MessageInfo();
        public MessageInfo NewMessageToSend
        {
            get { return _newMessageToSend; }
            set
            {
                _newMessageToSend = value;
                RaisePropertyChanged(() => NewMessageToSend);
                NewMessageToSend.ValueChanged -= NewMessageValueChanged;
                NewMessageToSend.ValueChanged += NewMessageValueChanged;
            }
        }

        private SerialInfo _selectedSerial;
        public SerialInfo SelectedSerial
        {
            get { return _selectedSerial; }
            set
            {
                _selectedSerial = value;
                RaisePropertyChanged(() => SelectedSerial);
                NewMessageToSend.Signature = SelectedSerial.Signature;
                NewMessageToSend.SerialNumber = SelectedSerial.SerialNumber;
                RaisePropertyChanged(() => NewMessageToSend);
                RaisePropertyChanged(() => SubmitCommand);
            }
        }

        public int SelectedCount
        {
            get
            {
                return ItemsOfContact.Count(c => c.IsSelected);
            }
        }

        public int TotleSendCount
        {
            get
            {
                int contentLength = NewMessageToSend.Content.Length + NewMessageToSend.Signature.Length + 2;

                if (contentLength <= 70)
                {
                    return SelectedCount;
                }
                else
                {
                    return ((contentLength + 64) / 65) * SelectedCount;
                }
            }
        }

        private bool _isBusy = false;
        public bool IsBusy
        {
            get { return _isBusy; }
            set
            {
                _isBusy = value;
                RaisePropertyChanged(() => IsBusy);
                RaisePropertyChanged(() => SubmitCommand);
                RaisePropertyChanged(() => CancelCommand);
            }
        }

        private bool _displayContactBook = true;
        public bool DisplayContactBook
        {
            get
            {
                return _displayContactBook;
            }
            set
            {
                _displayContactBook = value;
                RaisePropertyChanged(() => DisplayContactBook);
                RemoveOrAddContactBook(DisplayContactBook);
            }
        }
        #endregion

        #region Method & events
        private void NewContactValueChanged(object sender, PropertyArgs e)
        {
            RaisePropertyChanged(() => AddContactCommand);
        }

        private void contacts_SearchCompleted(object sender, ContactsSearchEventArgs e)
        {
            IEnumerable<Contact> items = e.Results.Where(c => c.PhoneNumbers.Count() > 0);
            if (items != null && items.Count() > 0)
            {
                foreach (Contact item in items)
                {
                    foreach (ContactPhoneNumber phone in item.PhoneNumbers)
                    {
                        string mobile = phone.PhoneNumber.Replace("(", "").Replace(")", "").Replace("-", "").Trim();
                        if (CommonClass.VerifyMobile(mobile) && ItemsOfContact.Count(c => c.Mobile == mobile) == 0)
                        {
                            ItemsOfContact.Add(new ContactInfo() { Name = item.DisplayName, Mobile = mobile, Stored = true });
                            RaisePropertyChanged(() => SelectedCount);
                        }
                    }
                }
            }
            SetItemEvent();
            
            RaisePropertyChanged(() => SelectedCommand);
            RaisePropertyChanged(() => UnselectedCommand);
            RaisePropertyChanged(() => TotleSendCount);
            RaisePropertyChanged(() => SubmitCommand);
            RaisePropertyChanged(() => CleanCommand);
        }

        private void SetItemEvent()
        {
            foreach (ContactInfo item in ItemsOfContact)
            {
                item.ValueChanged -= ContactItemValueChanged;
                item.ValueChanged += ContactItemValueChanged;
            }
        }

        private void CleanContacts()
        {
            ItemsOfContact.Clear();
            if (DisplayContactBook)
            {
                contacts.SearchAsync("", FilterKind.None, null);
            }
            RaisePropertyChanged(() => ItemsOfContact);
            RaisePropertyChanged(() => SelectedCount);
            RaisePropertyChanged(() => TotleSendCount);
            RaisePropertyChanged(() => CleanCommand);
            RaisePropertyChanged(() => SubmitCommand);
        }

        private void RemoveOrAddContactBook(bool displayContactBook)
        {
            if (!displayContactBook)
            {
                for (int i = 0; i < ItemsOfContact.Count();)
                {
                    if (ItemsOfContact.ElementAt(i).Stored)
                    {
                        ItemsOfContact.RemoveAt(i);
                    }
                    else
                    {
                        i++;
                    }
                }
                RaisePropertyChanged(() => ItemsOfContact);
                RaisePropertyChanged(() => SelectedCount);
                RaisePropertyChanged(() => TotleSendCount);
                RaisePropertyChanged(() => CleanCommand);
                RaisePropertyChanged(() => SubmitCommand);
            }
            else
            {
                contacts.SearchAsync("", FilterKind.None, null);
            }
        }

        private void ContactItemValueChanged(object sender, PropertyArgs e)
        {
            RaisePropertyChanged(() => SelectedCount);
            RaisePropertyChanged(() => SubmitCommand);
            RaisePropertyChanged(() => SelectedCommand);
            RaisePropertyChanged(() => UnselectedCommand);
            RaisePropertyChanged(() => TotleSendCount);
        }

        private void NewMessageValueChanged(object sender, PropertyArgs e)
        {
            RaisePropertyChanged(() => SubmitCommand);
            RaisePropertyChanged(() => TotleSendCount);
        }

        private void SoapClientSendSMSCompleted(object sender, SendSMSCompletedEventArgs e)
        {
            if (e.Error == null)
            {
                if (e.Result.code == 0)
                {
                    NewMessageToSend.SendId = e.Result.sendid;
                    NewMessageToSend.Status = MessageStatus.Succeed;

                    SerialInfo serial = Database.CollectionOfSerialNumbers.FirstOrDefault(s => s.SerialNumber == SelectedSerial.SerialNumber);
                    serial.SentCount += TotleSendCount;
                }
                else
                {
                    ShowResult<ResultCodeValue>(e.Result.code);
                    //MessageBox.Show(((ResultCodeValue)e.Result.code).ToString());
                }
            }
            else
            {
                MessageBox.Show(e.Error.Message);
            }

            NewMessageToSend.Time = DateTime.Now;

            Database.CollectionOfMessages.InsertOnSubmit(NewMessageToSend);

            Database.CollectionOfMobiles.InsertAllOnSubmit(ItemsOfContact.Where(c => c.IsSelected).Select(c => new MessageMobileInfo()
            {
                Mobile = c.Mobile,
                MessageGuid = NewMessageToSend.Guid,
                SendId = e.Result.sendid,
                Time = DateTime.Now
            }));

            Submit();

            MessageBox.Show(Application.Current.FindResource<string>(LanguageKeys.IDS_NOTIFICATION_DONE));
            //NavigateBack();
            IsBusy = false;
        }
        #endregion

        #region Commands
        public ICommand AddContactCommand
        {
            get
            {
                return new GenericCommand()
                {
                    CanExecuteCallback = delegate { return CommonClass.VerifyMobile(NewContactToAdd.Mobile) && ItemsOfContact.Count(c => c.Mobile == NewContactToAdd.Mobile) == 0; },
                    ExecuteCallback = delegate
                    {
                        ItemsOfContact.Add(NewContactToAdd);
                        NewContactToAdd = new ContactInfo();
                        NewContactToAdd.ValueChanged -= NewContactValueChanged;
                        NewContactToAdd.ValueChanged += NewContactValueChanged;
                        SetItemEvent();
                        RaisePropertyChanged(() => AddContactCommand);
                        RaisePropertyChanged(() => ItemsOfContact);
                        RaisePropertyChanged(() => SelectedCount);
                        RaisePropertyChanged(() => SubmitCommand);
                        RaisePropertyChanged(() => SelectedCommand);
                        RaisePropertyChanged(() => UnselectedCommand);
                        RaisePropertyChanged(() => TotleSendCount);
                    }
                };
            }
        }

        public ICommand SubmitCommand
        {
            get
            {
                return new GenericCommand()
                {
                    CanExecuteCallback = delegate
                    {
                        return SelectedSerial != null && NewMessageToSend.Content.Length > 0 && SelectedCount > 0 && !IsBusy;
                    },
                    ExecuteCallback = delegate {
                        IsBusy = true;
                        string mobile = string.Join(",", ItemsOfContact.Select(c => c.Mobile).ToArray());
                        SoapClient.SendSMSAsync(
                            SelectedSerial.SerialNumber,
                            SelectedSerial.Password,
                            NewMessageToSend.Content,
                            mobile,
                            NewMessageToSend.Extension,
                            "",
                            NewMessageToSend.IsSign ? "Y" : "N",
                            NewMessageToSend.Signature);
                    }
                };
            }
        }

        public ICommand CancelCommand
        {
            get
            {
                return new GenericCommand()
                {
                    CanExecuteCallback = delegate { return !IsBusy; },
                    ExecuteCallback = delegate {
                        NavigateBack();
                    }
                };
            }
        }

        public ICommand SelectedCommand
        {
            get
            {
                return new GenericCommand()
                {
                    CanExecuteCallback = delegate { return SelectedCount != ItemsOfContact.Count; },
                    ExecuteCallback = delegate {
                        foreach (ContactInfo item in ItemsOfContact)
                        {
                            item.IsSelected = true;
                        }
                        RaisePropertyChanged(() => ItemsOfContact);
                        RaisePropertyChanged(() => SelectedCount);
                        RaisePropertyChanged(() => TotleSendCount);
                        RaisePropertyChanged(() => SubmitCommand);
                        
                    }
                };
            }
        }

        public ICommand UnselectedCommand
        {
            get
            {
                return new GenericCommand()
                {
                    CanExecuteCallback = delegate { return SelectedCount != 0; },
                    ExecuteCallback = delegate
                    {
                        foreach (ContactInfo item in ItemsOfContact)
                        {
                            item.IsSelected = false;
                        }
                        RaisePropertyChanged(() => ItemsOfContact);
                        RaisePropertyChanged(() => SelectedCount);
                        RaisePropertyChanged(() => TotleSendCount);
                        RaisePropertyChanged(() => SubmitCommand);
                        
                    }
                };
            }
        }

        public ICommand CleanCommand
        {
            get
            {
                return new GenericCommand()
                {
                    CanExecuteCallback = delegate { return ItemsOfContact.Count > 0; },
                    ExecuteCallback = delegate { CleanContacts(); }
                };
            }
        }
        #endregion
    }
}
